package com.cl.ks.service;

import cn.hutool.core.io.IoUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.cl.ks.config.ValueConfig;
import com.cl.ks.entity.*;
import com.cl.ks.repository.*;
import com.cl.ks.utils.DbUtil;
import com.cl.ks.utils.QueryDslUtil;
import com.jandar.pile.common.util.IParamBundle;
import com.jandar.pile.common.util.JwtUtil;
import com.jandar.pile.common.util.PageBundle;
import com.jandar.pile.common.util.ParamBundle;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.transaction.Transactional;
import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static com.cl.ks.constant.QTableConstant.*;

/**
 * @author chenyitao
 * @date 2021/4/19
 */
@Service
@EnableAsync(proxyTargetClass = true)
@EnableCaching(proxyTargetClass = true)
public class FilterService extends BaseManagerService {
    private final FilterAsyncService filterAsyncService;
    private final ValueConfig valueConfig;
    private final DbUtil dbUtil;
    private final JwtUtil<Long, Long> jwtUtil;
    private final AtomicBoolean clueAutoResultIsRun = new AtomicBoolean(false);

    private final KsRuleRepository ksRuleRepository;

    private final RlRuleTableRepository rlRuleTableRepository;

    private final KsFilterLogRepository ksFilterLogRepository;

    private final SysSourceMappingTableFieldRepository sysSourceMappingTableFieldRepository;

    private final KsFilterStatisticsRepository ksFilterStatisticsRepository;

    private final KsClassFieldRepository ksClassFieldRepository;

    private final ClueAutoResultRepository clueAutoResultRepository;

    private final KsFilterRepository ksFilterRepository;

    private final KsFilterResultRepository ksFilterResultRepository;

    private final JPAQueryFactory queryFactory;
    final BlockingQueue<Integer> blockingQueue = new ArrayBlockingQueue<>(2000000);

    final Map<String, Map<String, String>> dbCodeTableAndResultPowerFieldMapping = new HashMap<>();

    public FilterService(FilterAsyncService filterAsyncService, ValueConfig valueConfig, DbUtil dbUtil, JwtUtil<Long, Long> jwtUtil, KsRuleRepository ksRuleRepository, RlRuleTableRepository rlRuleTableRepository, KsFilterLogRepository ksFilterLogRepository, SysSourceMappingTableFieldRepository sysSourceMappingTableFieldRepository, KsFilterStatisticsRepository ksFilterStatisticsRepository, KsClassFieldRepository ksClassFieldRepository, ClueAutoResultRepository clueAutoResultRepository, KsFilterRepository ksFilterRepository, KsFilterResultRepository ksFilterResultRepository, JPAQueryFactory queryFactory) {
        this.clueAutoResultRepository = clueAutoResultRepository;
        this.filterAsyncService = filterAsyncService;
        this.valueConfig = valueConfig;
        this.dbUtil = dbUtil;
        this.jwtUtil = jwtUtil;
        this.ksRuleRepository = ksRuleRepository;
        this.rlRuleTableRepository = rlRuleTableRepository;
        this.ksFilterLogRepository = ksFilterLogRepository;
        this.sysSourceMappingTableFieldRepository = sysSourceMappingTableFieldRepository;
        this.ksFilterStatisticsRepository = ksFilterStatisticsRepository;
        this.ksClassFieldRepository = ksClassFieldRepository;
        this.ksFilterRepository = ksFilterRepository;
        this.ksFilterResultRepository = ksFilterResultRepository;
        this.queryFactory = queryFactory;
    }

    public List<String> examFilter(Integer filterId) {
        List<String> res = new ArrayList<>();
        KsFilter filter = ksFilterRepository.getById(filterId);
        String filterBundle = filter.getFilterBundle();
        FilterBundle bundle = JSONObject.parseObject(filterBundle, FilterBundle.class);
        List<FilterParam> filterParams = bundle.getFilterParams();
        for (int i = 0; i < filterParams.size(); i++) {
            FilterParam filterParam = filterParams.get(i);
            String tableName = filterParam.getTableName();
            String dbCode = filterParam.getDbCode();

            SysSourceMappingTable sysSourceMappingTable = queryFactory.selectFrom(qSysSourceMappingTable).where(qSysSourceMappingTable.tableName.eq(tableName).and(qSysSourceMappingTable.dbCode.eq(dbCode))).fetchFirst();

            if (sysSourceMappingTable == null) {
                res.add("检索管理未配置,TableName:" + tableName + ",DbCode:" + dbCode);
                continue;
            }
            Integer ksRuleId = filterParam.getKsRuleId();
            Optional<KsRule> ksRule = ksRuleRepository.findById(ksRuleId);
            if (!ksRule.isPresent()) {
                res.add("规则ID不存在：" + ksRuleId);
                continue;
            }

            RlRuleTable rlRuleTable = queryFactory.selectFrom(qRlRuleTable).where(qRlRuleTable.tableName.eq(tableName).and(qRlRuleTable.dbCode.eq(dbCode).and(qRlRuleTable.ruleId.eq(ksRuleId)))).fetchFirst();
            if (rlRuleTable == null) {
                res.add("规则关联表未配置，KsRuleId：" + ksRuleId+",TableName："+tableName+",DbCode:"+dbCode);
                continue;
            }

//            RlRuleField rlRuleField = queryFactory.selectFrom(qRlRuleField).where(qRlRuleField.ruleId.eq(ksRuleId).and(qRlRuleField.))
            res.add("success");

        }
        return res;
    }

    public Integer newFilter(FilterBundle filterBundle) {
        String systemCode = jwtUtil.getSystemCode(filterBundle.auth);
        KsFilter ksFilter = new KsFilter();
        ksFilter.setFilterName(filterBundle.getFilterName());
        filterBundle.setMatch(0);
        filterBundle.setNotMatch(0);
        filterBundle.setTotal(0);
        ksFilter.setFilterBundle(JSONObject.toJSONString(filterBundle));
        ksFilter.setCreateTime(LocalDateTime.now());
//        ksFilter.setSaveFilePath(String.format("%s/%s.xlsx", valueConfig.getFileSavePath(), UUID.randomUUID()));
        ksFilter.setSaveFilePath("");
        ksFilter.setStatus(0);
        ksFilter.setIsTask(filterBundle.isTask);
        ksFilter.setClassification("\"" + filterBundle.classification + "\"");
        ksFilter.setStartTime(filterBundle.startTime);
        ksFilter.setEndTime(filterBundle.endTime);
        ksFilter.setPower(filterBundle.power);
        ksFilter.setResultPower(filterBundle.resultPower);
        ksFilter.setSystemCode(systemCode);
        // 使用 ks_table 表字段
        ksFilter.setUserIds("," + filterBundle.getUserId() + ",");
        ksFilter.setRoleIds(",1," + filterBundle.getRoleId() + ",");

        ksFilterRepository.save(ksFilter);
        return ksFilter.getId();
    }

    public FilterAsyncService.FilterProgress getProgress(Integer filterId) {
        return filterAsyncService.getProgress(filterId);
    }

    public Integer newFilterTaskReturnId(FilterBundle filterBundle) {
        Integer filterId = newFilter(filterBundle);
        filterAsyncService.filterAsync(filterId, filterBundle, null);
        return filterId;

    }

    public ResponseEntity<Object> newFilterTask(FilterBundle filterBundle) {
        Integer filterId = newFilter(filterBundle);
        filterAsyncService.filterAsync(filterId, filterBundle, null);
        return ResponseEntity.ok().body("任务已提交");
    }


    public ResponseEntity<Object> updateFilterTask(String auth, FilterBundle filterBundle) {
        KsFilter ksFilter = ksFilterRepository.getById(filterBundle.id);
        String systemCode = jwtUtil.getSystemCode(auth);
        ksFilter.setFilterName(filterBundle.getFilterName());
        ksFilter.setFilterBundle(JSONObject.toJSONString(filterBundle));
        ksFilter.setClassification("\"" + filterBundle.classification + "\"");
        ksFilter.setStartTime(filterBundle.startTime);
        ksFilter.setEndTime(filterBundle.endTime);
        ksFilter.setPower(filterBundle.power);
        ksFilter.setResultPower(filterBundle.resultPower);
        ksFilter.setIsTask(filterBundle.isTask);
        ksFilter.setSystemCode(systemCode);

        // 使用 ks_table 表字段
        ksFilter.setUserIds("," + filterBundle.getUserId() + ",");
        ksFilter.setRoleIds(",1," + filterBundle.getRoleId() + ",");
        ksFilterRepository.save(ksFilter);

        return ResponseEntity.ok().body("操作成功");
    }


    @Transactional
    public ResponseEntity<Object> editFilterTask(FilterBundle filterBundle) {
        Integer id = filterBundle.getId();
        Boolean isTask = filterBundle.getIsTask();
        Boolean pushClue = filterBundle.getPushClue();
        Integer status = filterBundle.getStatus();
        if (isTask != null) {
            queryFactory.update(qKsFilter).set(qKsFilter.isTask, isTask).where(qKsFilter.id.eq(id)).execute();
            return ResponseEntity.ok().body(isTask ? "定时任务开启" : "定时任务关闭");
        }
        if (pushClue != null) {
            queryFactory.update(qKsFilter).set(qKsFilter.pushClue, pushClue).where(qKsFilter.id.eq(id)).execute();
            return ResponseEntity.ok().body(pushClue ? "推送线索开启" : "推送线索关闭");
        }
        if (status != null) {
            queryFactory.update(qKsFilter).set(qKsFilter.status, status).where(qKsFilter.id.eq(id)).execute();
            return ResponseEntity.ok().body(status == 2 ? "该任务已下线" : "该任务已上线");
        }


        return null;

    }


    public ResponseEntity<Object> filterTaskList(String auth, Map<String, Object> param) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
        IParamBundle paramBundle = ParamBundle.newBundle(param);
        PageBundle pageBundle = paramBundle.getPageBundle();
        String filterName = paramBundle.getString("filterName");
        String startTime = paramBundle.getString("startTime");
        String endTime = paramBundle.getString("endTime");
        String ruleCondition = paramBundle.getString("ruleCondition");
        String userId = String.valueOf(jwtUtil.getUserId(auth));
        String roleId = String.valueOf(jwtUtil.getRoleId(auth));
        String systemCode = jwtUtil.getSystemCode(auth);
        String depId = String.valueOf(jwtUtil.getDepId(auth));
        String classification = paramBundle.getString("classification");

        BooleanExpression booleanExpression = QueryDslUtil.generatePowerExpression(qKsFilter, qKsFilter.power, userId, roleId, depId);
        if (StringUtils.isNotBlank(ruleCondition)) {
            booleanExpression = booleanExpression.and(qKsFilter.filterBundle.contains(ruleCondition));
        }
        if (StringUtils.isNotBlank(systemCode)) {
            booleanExpression = booleanExpression.and(qKsFilter.systemCode.eq(systemCode).or(qKsFilter.systemCode.isNull()));
        }
        if (StringUtils.isNotBlank(filterName)) {
            booleanExpression = booleanExpression.and(qKsFilter.filterName.contains(filterName));
        }
        if (StringUtils.isNotBlank(startTime)) {
            try {
                booleanExpression = booleanExpression.and(qKsFilter.createTime.gt(dateToLocalDateTime(simpleDateFormat.parse(startTime))));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (StringUtils.isNotBlank(endTime)) {
            try {
                booleanExpression = booleanExpression.and(qKsFilter.createTime.lt(dateToLocalDateTime(new Date(simpleDateFormat.parse(endTime).getTime() + 60 * 60 * 24 * 1000))));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (StringUtils.isNotBlank(classification)) {
            booleanExpression = booleanExpression.and(
                    qKsFilter.classification.contains("," + classification + ",")
                            .or(qKsFilter.classification.contains("\"" + classification + ","))
                            .or(qKsFilter.classification.contains("," + classification + "\""))
                            .or(qKsFilter.classification.contains("\"" + classification + "\"")));
        }
        List<KsFilterEx> ksFilterExes =
                queryFactory.selectFrom(qKsFilter).where(booleanExpression).orderBy(qKsFilter.id.desc()).offset(pageBundle.getStart()).limit(pageBundle.getSize())
                        .fetch().stream().map(item -> {
                            KsFilterEx ksFilterEx = new KsFilterEx();
                            BeanUtils.copyProperties(item, ksFilterEx);
                            return ksFilterEx;
                        })
                        .peek(e -> {
                            e.setSaveFilePath(null);
                            e.setFilterBundleJson(e.getFilterBundle().replace("\n", "").replace("\\\\", "\\"));
                            e.setFilterBundle(null);
                            if (filterAsyncService.getProgressMap().containsKey(e.getId())) {
                                e.setProgress(filterAsyncService.getProgressMap().get(e.getId()));
                            }

                            Long runCount = queryFactory.select(qKsFilterLog.count()).from(qKsFilterLog).where(qKsFilterLog.filterId.eq(e.getId())).fetchOne();
                            e.setRunCount(runCount);
                            FilterBundle filterBundle = JSONObject.parseObject(e.filterBundleJson, FilterBundle.class);
                            Integer match = filterBundle.getMatch() == null ? 0 : filterBundle.getMatch();
                            int total = 0;
                            for (FilterParam filterParam : filterBundle.getFilterParams()) {
                                if (filterParam.getLastPosition() != null) {
                                    total += filterParam.getLastPosition();
                                }
                            }
                            filterBundle.setNotMatch(total - match);
                            filterBundle.setTotal(total);
                            e.setFilterBundleJson(JSONObject.toJSONString(filterBundle));
                            e.setClueCount(match);
                            e.setSourceCount(total);
                            Long availableCount = queryFactory.select(qKsFilterResult.count()).from(qKsFilterResult).where(qKsFilterResult.filterId.eq(e.getId()).and(qKsFilterResult.isAvailable.eq(1))).fetchOne();
                            e.setAvailableCount(availableCount);
                            Long processCount = queryFactory.select(qKsFilterResult.count()).from(qKsFilterResult).where(qKsFilterResult.filterId.eq(e.getId()).and(qKsFilterResult.isAvailable.isNotNull())).fetchOne();
                            e.setProcessCount(processCount);
                        })
                        .collect(Collectors.toList());

        Long count = queryFactory.select(qKsFilter.count()).from(qKsFilter).where(booleanExpression).fetchOne();

        JSONObject page = new JSONObject();
        page.put("list", ksFilterExes);
        page.put("page", pageBundle.getPage());
        page.put("size", pageBundle.getSize());
        page.put("count", count);
        return ResponseEntity.ok().body(page);
    }


    public ResponseEntity<Object> filterTaskDetail(Map<String, Object> param) {
        JSONObject page = new JSONObject();

        IParamBundle bundle = ParamBundle.newBundle(param);
        PageBundle pageBundle = bundle.getPageBundle();
        Integer recordId = bundle.getInt("recordId");
        String errors = bundle.getString("errors");
        String success = bundle.getString("success", "");
        Integer ruleId = bundle.getInt("ruleId");
        Integer isAvailable = bundle.getInt("isAvailable", -1);

        BooleanExpression booleanExpression = qKsFilterResult.filterId.eq(recordId);

        if (isAvailable != null && isAvailable != -1) {
            booleanExpression = booleanExpression.and(qKsFilterResult.isAvailable.eq(isAvailable));
        }
        if (ruleId != null && ruleId != 0) {
            booleanExpression = booleanExpression.and(qKsFilterResult.ruleId.eq(ruleId));
        } else {
            KsFilter filter = queryFactory.selectFrom(qKsFilter).where(qKsFilter.id.eq(recordId)).fetchFirst();
            List<FilterParam> filterParams = JSONObject.parseObject(filter.getFilterBundle(), FilterBundle.class).getFilterParams();
            List<Map<String, Object>> ruleList = filterParams.stream()
                    .map(item -> {
                        Expression[] fields = {qKsRule.id, qKsRule.ruleName};
                        Tuple tuple = queryFactory.select(fields).from(qKsRule).where(qKsRule.id.eq(item.ksRuleId)).fetchOne();
                        return QueryDslUtil.tupleToMap(tuple, fields);
                    })
                    .collect(Collectors.toList());
            page.put("ruleList", ruleList);
        }
        if (StringUtils.isNotBlank(errors)) {
            booleanExpression = booleanExpression.and(qKsFilterResult.errors.contains(errors));
        }
        if (success.matches("true|false")) {
//            KsFilter filter = dslContext.selectFrom(KS_FILTER).where(KS_FILTER.ID.eq(recordId)).fetchAnyInto(KsFilter.class);
            boolean successVal = Boolean.parseBoolean(success);
//            condition = condition.and(KS_FILTER_RESULT.SUCCESS.eq(successVal));
            if (successVal) {
                booleanExpression = booleanExpression.and(qKsFilterResult.errors.eq(""));
            } else {
                booleanExpression = booleanExpression.and(qKsFilterResult.errors.ne(""));
            }
        }

        List<KsFilterResultEx> resultList =
                queryFactory.selectFrom(qKsFilterResult).where(booleanExpression).offset(pageBundle.getStart()).limit(pageBundle.getSize()).fetch().stream().map(item -> {
                            KsFilterResultEx ksFilterResultEx = new KsFilterResultEx();
                            BeanUtils.copyProperties(item, ksFilterResultEx);
                            return ksFilterResultEx;
                        })
                        .peek(e -> {
                            e.setResultJson(mapToFieldValueArray(e.getResult()));
                            e.setCompareJsonStr(e.getCompareJson());
                            e.setResult(null);
                            e.setCompareJson(null);
                        })
                        .collect(Collectors.toList());
        Long count = queryFactory.select(qKsFilterResult.count()).from(qKsFilterResult).where(booleanExpression).fetchOne();
        page.put("list", resultList);
        page.put("page", pageBundle.getPage());
        page.put("size", pageBundle.getSize());
        page.put("count", count);
        return ResponseEntity.ok().body(page);
    }

    public String mapToFieldValueArray(String result) {
        if (result == null || result.trim().startsWith("[")) {
            return result;
        }
        JSONObject source = JSONObject.parseObject(result);
        JSONArray target = new JSONArray();
        source.forEach((key, value) -> {
            JSONObject item = new JSONObject();
            item.put("field", key);
            item.put("value", value);
            item.put("fieldLastName", key);
            target.add(item);
        });
        return JSON.toJSONString(target);
    }

    public String fieldValueArrayToMap(String result) {
        if (result == null || result.trim().startsWith("{")) {
            return result;
        }
        JSONArray source = JSONArray.parseArray(result);
        JSONObject target = new JSONObject();
        for (int i = 0; i < source.size(); i++) {
            JSONObject item = source.getJSONObject(i);
            target.put(item.getString("field"), item.getString("value"));
        }
        return target.toJSONString();
    }

    public void getFilterFile(Integer id, HttpServletResponse response) {
        try (ExcelWriter writer = ExcelUtil.getWriter()) {
            KsFilter ksFilter = queryFactory.selectFrom(qKsFilter).where(qKsFilter.id.eq(id)).fetchFirst();
            List<KsFilterResult> ksFilterResultList = queryFactory.selectFrom(qKsFilterResult).where(qKsFilterResult.filterId.eq(id)).fetch();
            List<String> dbCodeTableList = new ArrayList<>();
            List<JSONObject> list = ksFilterResultList.stream().peek(ksFilterResult -> {
                String dbCodeTable = ksFilterResult.getDbCode() + ":" + ksFilterResult.getDataSourceName();
                if (!dbCodeTable.contains("null") && !dbCodeTableList.contains(dbCodeTable)) {
                    dbCodeTableList.add(dbCodeTable);
                }
            }).map(ksFilterResult -> {
                JSONObject res = JSONObject.parseObject(fieldValueArrayToMap(ksFilterResult.getResult()));
                res.put("errors", ksFilterResult.getErrors());
                res.put("tips", ksFilterResult.getTips());
                return res;
            }).collect(Collectors.toList());
            List<SysSourceMappingTableField> fieldList = new ArrayList<>();
            dbCodeTableList.forEach(dbCodeTable -> {
                String dbCode = dbCodeTable.split(":")[0];
                String table = dbCodeTable.split(":")[1];
                fieldList.addAll(queryFactory.selectFrom(qSysSourceMappingTableField).where(qSysSourceMappingTableField.tableName.eq(table).and(qSysSourceMappingTableField.dbCode.eq(dbCode))).fetch());
            });
            if (list.isEmpty()) {
                return;
            }
            fieldList.stream()
                    .forEach(field -> {
                        String fieldName = field.getTableFieldName();
                        if (StringUtils.isBlank(fieldName)) {
                            fieldName = field.getTableField();
                        }
                        writer.addHeaderAlias(field.getTableField(), fieldName);
                    });
            AtomicInteger atomicInteger = new AtomicInteger(0);
            list.get(0).forEach((key, value) -> {
                writer.setColumnWidth(atomicInteger.getAndAdd(1), 20);
            });

            list.stream().map(jsonObject -> {
                try {
                    if (jsonObject.toJSONString().length() < 32767) {
                        return jsonObject;
                    } else {
                        jsonObject.entrySet().forEach(itemEntry -> {
                            String itemValue = String.valueOf(itemEntry.getValue());
                            if (itemValue.length() > 32767) {
                                String trimValue = itemValue.replaceAll("\\s+", "");
                                if (trimValue.length() > 32767) {
                                    itemEntry.setValue("数据超长已截断：" + trimValue.substring(0, 32700));
                                } else {
                                    itemEntry.setValue(trimValue);
                                }
                            }
                        });
                    }
                    return jsonObject;
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return null;
            }).filter(Objects::nonNull).collect(Collectors.toList());

            writer.addHeaderAlias("tips", "提示信息");
            writer.addHeaderAlias("errors", "线索信息");
            writer.setOnlyAlias(false);
            writer.write(list, true);
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
            response.setHeader("Content-Disposition", "attachment;filename=result" + ksFilter.getId() + ".xlsx");
            ServletOutputStream out = response.getOutputStream();
            writer.flush(out, true);
            IoUtil.close(out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public ResponseEntity<Object> rerunAll() {
        List<Integer> list = queryFactory.select(qKsFilter.id).from(qKsFilter).fetch();
        list.forEach(r -> {
            try {
                Thread.sleep(10);
                rerunFilterTask(r, null);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
//        clueAutoResult(null);
        return null;
    }


    public ResponseEntity<Object> rerunFilterTask(Integer recordId, JSONObject taskListParam) {
        KsFilter ksFilter = queryFactory.selectFrom(qKsFilter).where(qKsFilter.id.eq(recordId)).fetchOne();
        if (ksFilter == null) {
            return ResponseEntity.badRequest().body("无效id");
        }
        if (ksFilter.getStatus() == 2) {
            return ResponseEntity.badRequest().body("该任务暂未上线");
        }
        FilterBundle filterBundle = JSONObject.parseObject(ksFilter.getFilterBundle().toString().replace("\n", "").replace("\\\\", "\\"), FilterBundle.class);

        ksFilter.setStatus(0);
        ksFilterRepository.save(ksFilter);
        filterBundle.setRerun(true);
        filterBundle.setTotal(0);
        filterBundle.setMatch(0);

        ksFilterResultRepository.deleteByIdAndIsAvailableIsNull(ksFilter.getId());
        filterAsyncService.filterAsync(ksFilter.getId(), filterBundle, taskListParam);
        return ResponseEntity.ok().body("任务已提交");
    }


    public ResponseEntity<Object> listFilterLog(KsFilter filter) {
        List<KsFilterLog> ksFilterLogList = queryFactory.selectFrom(qKsFilterLog).where(qKsFilterLog.filterId.eq(filter.getId())).fetch();
        return ResponseEntity.ok().body(createResult(true, "查询成功", ksFilterLogList));
    }


    @Transactional
    public ResponseEntity<Object> deleteFilterRecord(Integer recordId) {
        KsFilter filter = queryFactory.selectFrom(qKsFilter).where(qKsFilter.id.eq(recordId)).fetchOne();

        if (filter == null) {
            return ResponseEntity.ok().body(createMessage(false, "删除失败"));
        }
        queryFactory.delete(qKsFilterResult).where(qKsFilterResult.filterId.eq(recordId)).execute();
        ksFilterRepository.delete(filter);
        return ResponseEntity.ok().body(createMessage(true, "删除成功"));
    }


    public File getIncrementFilterFile(String id) {
        KsIncrement ksIncrementRecord = queryFactory.selectFrom(qKsIncrement).where(qKsIncrement.id.eq(id)).fetchFirst();
        if (ksIncrementRecord != null) {
            return new File(ksIncrementRecord.getSaveFilePath());
        }
        return null;
    }


    public ResponseEntity<Object> updateConfigure(String tableName, Integer id) {
        List<KsFilter> filterRecords = queryFactory.selectFrom(qKsFilter).fetch();
        for (KsFilter ksFilter : filterRecords) {
            FilterService.FilterBundle filterBundle = JSONObject.parseObject(
                    ksFilter.getFilterBundle(), FilterService.FilterBundle.class);
            if (filterBundle.getFilterParams() != null) {
                for (FilterService.FilterParam filterParam : filterBundle.getFilterParams()) {
                    if (filterParam.getTableName().equals(tableName)) {
                        filterParam.setLastPosition(id);
                    }
                }
            }
            ksFilter.setFilterBundle(JSONObject.toJSONString(filterBundle));
            ksFilterRepository.save(ksFilter);
        }
        return ResponseEntity.ok().body("SUCCESS");
    }

    public ResponseEntity listFilterLogByRuleType(Map<String, Object> param) {
        JSONObject page = new JSONObject();

        IParamBundle bundle = ParamBundle.newBundle(param);
        PageBundle pageBundle = bundle.getPageBundle();
        String ruleType = bundle.getString("ruleType");
        List<KsFilterLog> filterLogList = queryFactory.select(qKsFilterLog).from(qKsFilterLog).leftJoin(qKsRule).on(qKsRule.id.eq(qKsFilterLog.ruleId)).where(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + ruleType + ",")).offset((pageBundle.getPage() - 1) * pageBundle.getSize()).limit(pageBundle.getSize()).orderBy(qKsFilterLog.id.desc()).fetch();
        Long count = queryFactory.select(qKsFilterLog.count()).from(qKsFilterLog).leftJoin(qKsRule).on(qKsRule.id.eq(qKsFilterLog.ruleId)).where(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + ruleType + ",")).fetchFirst();

        page.put("list", filterLogList);
        page.put("page", pageBundle.getPage());
        page.put("size", pageBundle.getSize());
        page.put("count", count);
        return ResponseEntity.ok(createResult(true, "查询成功", page));
    }

    public ResponseEntity listFilterLogByRuleId(Map<String, Object> param) {
        JSONObject page = new JSONObject();

        IParamBundle bundle = ParamBundle.newBundle(param);
        PageBundle pageBundle = bundle.getPageBundle();
        Integer ruleId = bundle.getInt("ruleId");
        List<KsFilterLog> filterLogList = queryFactory.selectFrom(qKsFilterLog).where(qKsFilterLog.ruleId.eq(ruleId)).offset((pageBundle.getPage() - 1) * pageBundle.getSize()).limit(pageBundle.getSize()).orderBy(qKsFilterLog.id.desc()).fetch();
        Long count = queryFactory.select(qKsFilterLog.count()).from(qKsFilterLog).where(qKsFilterLog.ruleId.eq(ruleId)).fetchFirst();

        page.put("list", filterLogList);
        page.put("page", pageBundle.getPage());
        page.put("size", pageBundle.getSize());
        page.put("count", count);
        return ResponseEntity.ok(createResult(true, "查询成功", page));
    }

    public ResponseEntity listFilterLogByRuleId(Integer ruleId) {
        List<KsFilterLog> filterLogList = queryFactory.selectFrom(qKsFilterLog).where(qKsFilterLog.ruleId.eq(ruleId)).orderBy(qKsFilterLog.id.desc()).fetch();
        return ResponseEntity.ok(createResult(true, "查询成功", filterLogList));
    }


    public ResponseEntity listFilterResultByArea(String startDate, String endDate) {
//        clueAutoResult();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");//注意月份是MM
        List<KsFilterResultEx> filterResultList = queryFactory.selectFrom(qKsFilterResult).where(qKsFilterResult.result.contains("余检").and(qKsFilterResult.errors.length().gt(0))).fetch().stream().map(item -> {
            KsFilterResultEx ksFilterResultEx = new KsFilterResultEx();
            BeanUtils.copyProperties(item, ksFilterResultEx);
            return ksFilterResultEx;
        }).collect(Collectors.toList());

        List<KsFilterResultEx> res = filterResultList.stream().filter(ksFilterResult -> {
            JSONObject object = JSONObject.parseObject(ksFilterResult.getResult());
            String dateValue = String.valueOf(object.getOrDefault("YSPJRQ", ""));
            try {
                Date date = simpleDateFormat.parse(dateValue);
                Date start = simpleDateFormat.parse(startDate);
                Date end = simpleDateFormat.parse(endDate);

                Calendar calendar = new GregorianCalendar();
                calendar.setTime(start);
                calendar.add(Calendar.DATE, -1);
                start = calendar.getTime();

                calendar.setTime(end);
                calendar.add(Calendar.DATE, 1);
                end = calendar.getTime();

                if (date.after(start) && date.before(end)) {
                    return true;
                }
            } catch (ParseException e) {
                e.printStackTrace();
            }
            return false;
        }).peek(e -> {
            e.setKsFilterName(queryFactory.select(qKsFilter.filterName).from(qKsFilter).where(qKsFilter.id.eq(e.getFilterId())).fetchFirst());
            e.setResultJson(mapToFieldValueArray(e.getResult()));
            e.setCompareJsonStr(e.getCompareJson());
            e.setResult(null);
            e.setCompareJson(null);
        }).collect(Collectors.toList());

        return ResponseEntity.ok(createResult(true, "查询成功", res));
    }


    public ResponseEntity listFilterLogByRuleType(String ruleType) {
        List<Integer> ruleIdList = queryFactory.select(qKsRule.id).from(qKsRule).where(Expressions.asString(",").concat(qKsRule.ruleType).concat(",").contains("," + ruleType + ",")).fetch();
        List<Integer> idList = queryFactory.select(qKsFilterLog.id.max()).from(qKsFilterLog).groupBy(qKsFilterLog.ruleId).having(qKsFilterLog.ruleId.count().goe(1)).fetch();

        Path[] fields = {qKsRule.isAvailable,
                qKsFilterLog.ruleId,
                qKsFilterLog.filterId,
                qKsFilterLog.filterName,
                qKsFilterLog.createTime,
                qKsFilterLog.ksMatch,
                qKsFilterLog.ksNoMatch,
                qKsFilterLog.sourceType,
                qKsRule.ruleName,
                qKsRule.ruleType,
                qKsRule.ruleExpressionJson,
                qKsRule.adminArea,
                qKsRule.description};
        List<Tuple> tupleList =
                queryFactory.select(fields)
                        .from(qKsFilterLog)
                        .leftJoin(qKsRule)
                        .on(qKsFilterLog.ruleId.eq(qKsRule.id))
                        .where(qKsFilterLog.id.in(idList).and(qKsFilterLog.ruleId.in(ruleIdList))).orderBy(qKsRule.updateTime.desc()).fetch();
        List<Map<String, Object>> result = QueryDslUtil.tupleListToMapList(tupleList, fields).stream()
                .peek(r -> r.put("rule_expression_json", r.get("ruleExpressionJson").toString()))
                .collect(Collectors.toList());
        return ResponseEntity.ok(createResult(true, "success", result));
    }


    public ResponseEntity listFilterStatisticsByRuleId(Integer ruleId) {
        List<KsFilterStatistics> filterStatisticsList = queryFactory.selectFrom(qKsFilterStatistics).where(qKsFilterStatistics.ruleId.eq(ruleId)).fetch();
        return ResponseEntity.ok(createResult(true, "查询成功", filterStatisticsList));
    }


    public ResponseEntity getSourceDataByFilterResultId(Integer filterResultId) {
        KsFilterResult filterResult = queryFactory.selectFrom(qKsFilterResult).where(qKsFilterResult.id.eq(filterResultId)).fetchFirst();
        if (filterResult == null) {
            return ResponseEntity.ok(createResult(false, "没有这个id", null));
        }
        String dataId = filterResult.getDataId();
        Integer ruleId = filterResult.getRuleId();
        String dataSourceName = filterResult.getDataSourceName();
        if (dataSourceName == null) {
            return ResponseEntity.ok(createResult(false, "该数据没有原数据表名", null));
        }

        String dbCode = queryFactory.select(qRlRuleTable.dbCode).from(qRlRuleTable).where(qRlRuleTable.ruleId.eq(ruleId).and(qRlRuleTable.tableName.eq(dataSourceName))).fetchFirst();

        List<Map<String, Object>> list = dbUtil.fetchSQL(dbCode, "select * from " + dataSourceName + " where id=" + dataId);
        if (list.isEmpty()) {
            return ResponseEntity.ok(createResult(false, "无数据", null));
        }
        return ResponseEntity.ok(createResult(true, "查询成功", list.get(0)));
    }


    @Transactional
    public void clueAutoResult(Integer id) {
        if (id != null) {
            blockingQueue.add(id);
        }

        if (clueAutoResultIsRun.get()) {
            return;
        }
        clueAutoResultIsRun.set(true);
        while (id == null || !blockingQueue.isEmpty()) {
            Integer filterId;
            if (id == null) {
                id = 0;
                filterId = null;
                queryFactory.delete(qClueAutoResult).execute();
            } else {
                filterId = blockingQueue.poll();
                queryFactory.delete(qClueAutoResult).where(qClueAutoResult.filterId.eq(filterId).and(qClueAutoResult.status.isNull())).execute();
            }
            Map<String, String> tableNameDbCodeAndAreaFieldMap = new HashMap<>();
            try {
                BooleanExpression booleanExpression = qKsFilterResult.errors.length().gt(0);
                if (filterId != null) {
                    booleanExpression = booleanExpression.and(qKsFilterResult.filterId.eq(filterId));
                }
                for (int i = 0; ; i++) {
                    List<Tuple> filterResultList = queryFactory.select(
                                    qKsFilterResult.filterId, qKsFilterResult.ruleId, qKsFilterResult.result,
                                    qKsFilterResult.dataId,
                                    qKsFilterResult.errors,
                                    qKsFilterResult.tips,
                                    qKsFilterResult.resultPower,
                                    qKsFilterResult.dbCode,
                                    qKsFilterResult.dataSourceName,
                                    qKsFilter.filterName,
                                    qKsFilter.filterBundle,
                                    qKsRule.ruleName,
                                    qKsRule.ruleType)
                            .from(qKsFilterResult)
                            .leftJoin(qKsFilter).on(qKsFilter.id.eq(qKsFilterResult.filterId))
                            .leftJoin(qKsRule).on(qKsRule.id.eq(qKsFilterResult.ruleId))
                            .where(booleanExpression)
                            .offset(i * 500L)
                            .limit(500)
                            .fetch();

                    if (filterResultList.isEmpty()) {
                        break;
                    }
                    List<ClueAutoResult> clueAutoResultList = new ArrayList<>();
                    filterResultList.stream().filter(r -> StringUtils.isNotBlank(r.get(qKsFilterResult.errors))).forEach(r -> {
                        String tableName = r.get(qKsFilterResult.dataSourceName);
                        String dbCode = r.get(qKsFilterResult.dbCode);
                        String tableNameDbCode = tableName + dbCode;
                        String areaField = null;
                        if (!tableNameDbCodeAndAreaFieldMap.containsKey(tableNameDbCode)) {
                            String thisField = queryFactory.select(qSysSourceMappingTableField.tableField).from(qSysSourceMappingTableField).where(qSysSourceMappingTableField.tableName.eq(tableName).and(qSysSourceMappingTableField.dbCode.eq(dbCode))).fetchFirst();
                            tableNameDbCodeAndAreaFieldMap.put(tableNameDbCode, thisField);
                        }
                        areaField = tableNameDbCodeAndAreaFieldMap.get(tableNameDbCode);

                        String areaValue = "";
                        String bmsahValue = "";
                        try {
                            JSONObject result = JSONObject.parseObject(r.get(qKsFilterResult.result));
                            if (areaField != null) {
                                if (Objects.requireNonNull(result).containsKey(areaField)) {
                                    areaValue = result.getString(areaField);
                                }
                            }
                            if (Objects.requireNonNull(result).containsKey("bmsah")) {
                                bmsahValue = result.getString("bmsah");
                            } else if (result.containsKey("BMSAH")) {
                                bmsahValue = result.getString("BMSAH");
                            }

                        } catch (Exception e) {
//                            e.printStackTrace();
                        }

                        String resultPower = handleResultPower(dbCode, tableName, r.get(qKsFilterResult.dataId), r.get(qKsFilterResult.resultPower));

                        ClueAutoResult clueAutoResult = new ClueAutoResult();
                        clueAutoResult.setFilterId(r.get(qKsFilterResult.filterId));
                        clueAutoResult.setRuleId(r.get(qKsFilterResult.ruleId));
                        clueAutoResult.setArea(areaValue);
                        clueAutoResult.setReason(r.get(qKsFilterResult.errors));
                        clueAutoResult.setTips(r.get(qKsFilterResult.tips));
                        clueAutoResult.setSourceId(r.get(qKsFilterResult.dataId));
                        clueAutoResult.setFilterName(r.get(qKsFilter.filterName));
                        clueAutoResult.setRuleName(r.get(qKsRule.ruleName));
                        clueAutoResult.setRuleType(r.get(qKsRule.ruleType));
                        clueAutoResult.setDataType("案件");
                        clueAutoResult.setDataId(bmsahValue);
                        clueAutoResult.setDbCode(dbCode);
                        clueAutoResult.setTableName(tableName);
                        clueAutoResult.setResultPower(resultPower);
                        clueAutoResultList.add(clueAutoResult);
                    });
                    clueAutoResultList.forEach(item -> {
                        try {
                            clueAutoResultRepository.save(item);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });

                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        dbCodeTableAndResultPowerFieldMapping.clear();
        clueAutoResultIsRun.set(false);
    }

    private String handleResultPower(String dbCode, String tableName, String sourceId, String resultPower) {
        Map<String, String> fieldMapping = new HashMap<>();
        fieldMapping.put("人员编码", "rybm");
        fieldMapping.put("部门编码", "depCode");
        fieldMapping.put("单位编码", "dwbm");
        Set<String> resultPowerItemList = fieldMapping.keySet();
        Map<String, String> resultPowerFieldMapping = new HashMap<>();
        String dbCodeTable = dbCode + ":" + tableName;
        if (dbCodeTableAndResultPowerFieldMapping.containsKey(dbCodeTable)) {
            resultPowerFieldMapping = dbCodeTableAndResultPowerFieldMapping.get(dbCodeTable);
        } else {
            List<SysSourceMappingTableField> fieldList = queryFactory.selectFrom(qSysSourceMappingTableField).where(qSysSourceMappingTableField.dbCode.eq(dbCode).and(qSysSourceMappingTableField.tableName.eq(tableName)).and(qSysSourceMappingTableField.tableFieldSearchType.in(resultPowerItemList).or(qSysSourceMappingTableField.tableFieldType.eq("primary")))).fetch();
            for (SysSourceMappingTableField field : fieldList) {
                if ("primary".equals(field.getTableFieldType())) {
                    resultPowerFieldMapping.put("id", field.getTableField());
                } else {
                    resultPowerFieldMapping.put(field.getTableField(), fieldMapping.get(field.getTableFieldSearchType()));
                }

            }
            dbCodeTableAndResultPowerFieldMapping.put(dbCodeTable, resultPowerFieldMapping);

        }
        String fields = resultPowerFieldMapping.keySet().stream().filter(item -> !item.equals("id")).collect(Collectors.joining(","));
        if (fields.isEmpty()) {
            return resultPower;
        }
        List<Map<String, Object>> list = dbUtil.fetchSQL(dbCode, "select " + fields + " from " + tableName + " where " + resultPowerFieldMapping.get("id") + "=" + sourceId);
        for (Map<String, Object> map : list) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (resultPowerFieldMapping.containsKey(entry.getKey())) {
                    String powerItem = resultPowerFieldMapping.get(entry.getKey());
                    if (powerItem != null) {
                        resultPower = resultPower + "," + powerItem + "_" + entry.getValue();
                    }
                }
            }
        }

        return resultPower;
    }


    /**
     * 将 Date 转为 LocalDate
     *
     * @param date
     * @return java.time.LocalDate;
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
    }


    @Transactional
    public ResponseEntity updateFilterResultAvailable(Integer resultId, Integer available) {
        Long res = queryFactory.update(qKsFilterResult).set(qKsFilterResult.isAvailable, available).where(qKsFilterResult.id.eq(resultId)).execute();
        return ResponseEntity.ok(res);
    }


    public ResponseEntity supervisePersonRelation(String name, String idCard, String dbCode) {
        JSONObject res = new JSONObject();

        res.put("name", name);
        res.put("idCard", idCard);
        res.put("dbCode", dbCode);

        StringBuilder condition = new StringBuilder("where litigant_name='").append(name).append("' ");
        if (StringUtils.isNotBlank(idCard)) {
            condition.append(" and id_card='").append(idCard).append("' ");
        }
        List<Map<String, Object>> sourceList = dbUtil.fetchSQL(dbCode, "select * from supervise_person_relation " + condition);

        if (sourceList.isEmpty()) {
            return ResponseEntity.ok(createResult(true, "此人无对应案件", res));
        }
        JSONArray targetList = new JSONArray();
        sourceList.forEach(source -> {
            JSONObject doc = new JSONObject();
            doc.put("doc", source);
            List<Map<String, Object>> personList = dbUtil.fetchSQL(dbCode, "select litigant_name,id_card from supervise_person_relation where doc_code='" + source.get("doc_code") + "'");
            List<JSONObject> list = personList.stream().map(p -> {
                JSONObject personItem = new JSONObject();
                personItem.put("name", p.get("litigant_name"));
                personItem.put("idCard", p.get("id_card"));
                List<Map<String, Object>> list1 = dbUtil.fetchSQL(dbCode, "select * from supervise_person_relation where doc_code='" + source.get("doc_code") + "'");
                personItem.put("docList", list1);
                return personItem;
            }).collect(Collectors.toList());

            doc.put("personList", list);
            targetList.add(doc);
        });

        res.put("docList", targetList);
        return ResponseEntity.ok(createResult(true, "查询成功", res));
    }

    @Data
    public static class FilterTaskParam {
        private Integer id;
        private Integer status;
        private Boolean isTask;
    }

    @Data
    public static class FilterBundle {
        private Integer id;

        private Integer status;
        private Boolean isTask;
        private Boolean pushClue;
        private String userId;

        private String roleId;

        private String filterName;

        private List<FilterParam> filterParams;

        private Integer match;

        private Integer notMatch;

        private Integer total;

        private Boolean rerun;

        private String incrementDownloadId;

        private Object classification;

        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime startTime;

        @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime endTime;

        private String power;
        private String resultPower;

        String auth;

    }

    @Data
    public static class FilterParam {

        private KsRule ksRule;
        private Integer ksRuleId;

        private String tableName;

        private List<String> tableNames;
        private List<String> joinOn;

        private String dbCode;

        private Integer lastPosition;

        private FilterCondition condition;

        private Integer match;
        private Integer total;
    }

    @Data
    public static class FilterCondition {
        private List<ClassCondition> classConditions;

        private Object primary;

        private Integer lastPosition;
    }

    @Data
    public static class ClassCondition {
        private String fieldName;

        private List<String> values;
    }

    @EqualsAndHashCode(callSuper = false)
    @Data
    public static class KsFilterResultEx extends KsFilterResult {
        private String ksFilterName;
        private String resultJson;
        private String compareJsonStr;
    }


    @EqualsAndHashCode(callSuper = true)
    @Data
    public static class KsFilterEx extends KsFilter {
        private FilterAsyncService.FilterProgress progress;

        private String filterBundleJson;

        // 线索数
        private Integer clueCount;
        // 已分析原始数据数
        private Integer sourceCount;
        // 有效数
        private Long availableCount;
        // 已处理数
        private Long processCount;
        // 任务执行次数
        private Long runCount;
    }


}
